package com.vinjogames.entities;

import com.vinjogames.util.AILogic;
import com.vinjogames.util.GameConVars;
import com.vinjogames.util.TechTree;

public class Player {
	protected Base homeBase;
	protected Resource[] resourcesOwned;
	protected Unit[] unitsOwned;
	protected TechTree myTechnologyTree;
	public AILogic myAI;
	protected int mType;
	protected boolean isFirstPlayer;//or is the left player

	//***Economy Values***
	protected int resourcesPerTurn;
	protected int resourcesRemaining;
	protected int unitsPerTurn;
	protected int unitsRemaining;
	protected float unitStartX;
	protected float unitStartY;
	protected double chanceAtFreeUnit;
	protected boolean hasFreeUnit;
	
	//***Technology Booleans***
	protected boolean moveAfterFire;
	protected boolean airDropEnabled;
	protected boolean reconTankUnlocked;
	protected boolean helicopterUnlocked;
	protected boolean artillaryUnlocked;
	protected boolean megaTankUnlocked;
	protected boolean sabotageUnlocked;
	protected boolean marketTankUnlocked;
	
	//***Combat Values***
	protected float damageMultiplier;
	protected float movementMultiplier;
	protected float rangeMultiplier;
	protected float damageTakenMultiplier;
	protected float accuracyMultiplier;
	protected float damageRadiusMultiplier;
	protected float unitHealPerTurn;
	protected int unitResourceCapContribution;
	
	//***Constructors***
	public Player(boolean left, int type) {
		initializeEconomyData();
		initializeTechBooleans();
		initializeCombatData();
		homeBase = null;
		resourcesOwned = new Resource[GameConVars.MAP_MAX_RESOURCES];
		isFirstPlayer = left;
		mType = type;
		if(mType == GameConVars.PLAYER_AI) {
			myAI = new AILogic(GameConVars.AI_BASIC);
		}
		myTechnologyTree = new TechTree();
	}
	//***End Constructors***
	
	//***Public Functions***
	public boolean createUnit() {
		return false;
	}
	
	public void destroyUnit(Unit u) {
		
	}
	
	public void newTurn() {
		unitsRemaining = unitsPerTurn;
		updatePlayerAP();
		calculateFreeUnit();
	}
	
	/**
	 * 
	 * Subtracts the given value, if possible, from the player's resource pool.
	 * 
	 * @param cost The amount to decrement player resources by.
	 * @return True if successful, false if player does not have enough resources remaining.
	 * 
	 */
	public boolean purchaseGeneric(int cost) {
		if(resourcesRemaining < cost) return false;
		resourcesRemaining -= cost;
		return true;
	}	
	
	/**
	 * 
	 * Attempts to update the player's remaining resources for a purchase and returns
	 * the result status of that purchase attempt.
	 * 
	 * @param cost The cost of the purchase.
	 * @return True if the purchase succeeded, false if the player does not have enough resources.
	 * 
	 */
	public boolean purchaseUnit(int cost) {
		if(cost > resourcesRemaining || unitsRemaining == 0) return false;
		resourcesRemaining -= cost;
		--unitsRemaining;
		return true;
	}
	
	/**
	 * Attempt to purchase a technology.
	 * 
	 * @param treeNum The tree in which the technology resides.
	 * @param techNum The technology number to purchase.
	 * @return True if successful, false if the player cannot purchase.
	 */
	public boolean purchaseTechnology(int treeNum, int techNum) {
		//If the technology is already owned or the requirements aren't met return false.
		if(!myTechnologyTree.doesPlayerOwnTech(treeNum, techNum)) {
			//Retrieve the cost and attempt to buy, return false if not enough money.
			int techCost = GameConVars.BUY_TECHNOLOGY_COSTS[myTechnologyTree.desiredTechDepth(techNum)];
			
			//Handle special cases for the tech and confirm cost.
			if(techCost > resourcesRemaining 
					|| !myTechnologyTree.playerResearchTechnology(this, treeNum, techNum)) return false;
			resourcesRemaining -= techCost;
			
			return true;
		}
		return false;
	}
	
	public boolean purchaseBaseUpgrade(int purchaseNum) {
		return homeBase.purchaseUpgrade(purchaseNum);
	}
	
	public void freeUnitUsed() {
		hasFreeUnit = false;
	}
	//***End Public Functions***
	
	//***Getters & Setters***
	public Unit[] getUnitsOwned() { return unitsOwned; }
	public Base getBase() { return homeBase; }
	public void setBase(Base b) { homeBase = b; }
	public void increaseResourcesPerTurn(int increase) { resourcesPerTurn += increase; }
	public float getUnitStartX() { return unitStartX; }
	public void setUnitStartX(float unitStartX) { this.unitStartX = unitStartX; }
	public float getUnitStartY() { return unitStartY; }
	public void setUnitStartY(float unitStartY) { this.unitStartY = unitStartY;	}
	public boolean isFirstPlayer() { return isFirstPlayer; }
	public float getDamageMultiplier() {return damageMultiplier; }
	public void setDamageMultiplier(float damageMultiplier) { this.damageMultiplier = damageMultiplier;	}
	public float getMovementMultiplier() { return movementMultiplier; }
	public void setMovementMultiplier(float movementMultiplier) { this.movementMultiplier = movementMultiplier;	}
	public float getRangeMultiplier() { return rangeMultiplier;	}
	public void setRangeMultiplier(float rangeMultiplier) {	this.rangeMultiplier = rangeMultiplier;	}
	public float getDamageTakenMultiplier() { return damageTakenMultiplier;	}
	public void setDamageTakenMultiplier(float damageTakenMultiplier) { this.damageTakenMultiplier = damageTakenMultiplier;	}
	public float getAccuracyMultiplier() { return accuracyMultiplier; }
	public void setAccuracyMultiplier(float accuracyMultiplier) { this.accuracyMultiplier = accuracyMultiplier;	}
	public float getDamageRadiusMultiplier() { return damageRadiusMultiplier; }
	public void setDamageRadiusMultiplier(float damageRadiusMultiplier) { this.damageRadiusMultiplier = damageRadiusMultiplier; }	
	public float getUnitHealPerTurn() { return unitHealPerTurn;	}
	public void setUnitHealPerTurn(float unitHealPerTurn) {	this.unitHealPerTurn = unitHealPerTurn;	}
	public int getUnitResourceCapContribution() { return unitResourceCapContribution;	}
	public void setUnitResourceCapContribution(int unitResourceCapContribution) {	this.unitResourceCapContribution = unitResourceCapContribution;	}
	public double getChanceAtFreeUnit() { return chanceAtFreeUnit; }
	public void setChanceAtFreeUnit(double chanceAtFreeUnit) { this.chanceAtFreeUnit = chanceAtFreeUnit;	}
	public int getType(){ return mType; }	
	public int getUnitsRemaining() { return unitsRemaining; }
	public int getResourcesRemaining(){ return resourcesRemaining; }
	public int getMaxResources(){ return GameConVars.PLAYER_MAX_AP_STORAGE; }
	public TechTree getMyTechnologyTree() {	return myTechnologyTree; }
	public boolean isMoveAfterFire() { return moveAfterFire; }
	public void setMoveAfterFire(boolean moveAfterFire) { this.moveAfterFire = moveAfterFire; }
	public boolean isAirDropEnabled() {	return airDropEnabled; }
	public void setAirDropEnabled(boolean airDropEnabled) {	this.airDropEnabled = airDropEnabled; }
	public boolean isReconTankUnlocked() { return reconTankUnlocked; }
	public void setReconTankUnlocked(boolean reconTankUnlocked) { this.reconTankUnlocked = reconTankUnlocked; }
	public boolean isHelicopterUnlocked() { return helicopterUnlocked; }
	public void setHelicopterUnlocked(boolean helicopterUnlocked) {	this.helicopterUnlocked = helicopterUnlocked; }
	public boolean isArtillaryUnlocked() { return artillaryUnlocked; }
	public void setArtillaryUnlocked(boolean artillaryUnlocked) { this.artillaryUnlocked = artillaryUnlocked; }
	public boolean isMegaTankUnlocked() { return megaTankUnlocked; }
	public void setMegaTankUnlocked(boolean megaTankUnlocked) {	this.megaTankUnlocked = megaTankUnlocked; }
	public boolean isSabotageUnlocked() { return sabotageUnlocked; }
	public void setSabotageUnlocked(boolean sabotageUnlocked) {	this.sabotageUnlocked = sabotageUnlocked; }
	public boolean isMarketTankUnlocked() {	return marketTankUnlocked; }
	public void setMarketTankUnlocked(boolean marketTankUnlocked) { this.marketTankUnlocked = marketTankUnlocked; }
	public boolean hasFreeUnit() { return hasFreeUnit; }
	public void upgradeUnitsPerTurn() { 
		if(unitsPerTurn > 1) return;
		++unitsPerTurn;
		++unitsRemaining;
	}	
	//***End Getters & Setters***
		
	
	//***Initializers***
	private void initializeEconomyData() {
		resourcesPerTurn = GameConVars.PLAYER_MINIMUM_INCOME;
		resourcesRemaining = GameConVars.PLAYER_STARTING_AP;
		unitsPerTurn = 1;
		unitsRemaining = 1;
		unitStartX = 0.0f;
		unitStartY = 0.0f;
		chanceAtFreeUnit = 0.0f;
		hasFreeUnit = false;
	}
	
	private void initializeTechBooleans() {
		moveAfterFire = airDropEnabled = reconTankUnlocked = helicopterUnlocked =
			artillaryUnlocked = megaTankUnlocked = sabotageUnlocked = marketTankUnlocked = false;
	}
	
	private void initializeCombatData() {
		damageMultiplier = movementMultiplier = rangeMultiplier = damageTakenMultiplier = 
				accuracyMultiplier = damageRadiusMultiplier = 1.0f;
		
		unitHealPerTurn = GameConVars.PLAYER_HEAL_PER_TURN;
		
		unitResourceCapContribution = GameConVars.PLAYER_UNIT_RESOURCE_CAP;
	}	
	//***End Initializers***
	
	//***Helper Functions***
	private void calculateFreeUnit() {
		if(!hasFreeUnit && Math.random() <= chanceAtFreeUnit) {
			hasFreeUnit = true;
		}
	}
	
	private void updatePlayerAP() {
		resourcesRemaining += resourcesPerTurn;
		resourcesRemaining = resourcesRemaining > GameConVars.PLAYER_MAX_AP_STORAGE ? GameConVars.PLAYER_MAX_AP_STORAGE : resourcesRemaining;
	}
	//***End Helper Functions***
}
